package cn.huiyunche.base.service.interfaces.impl;

import cn.huiyunche.base.service.constant.App;
import cn.huiyunche.base.service.enums.*;
import cn.huiyunche.base.service.framework.utils.HYCUtils;
import cn.huiyunche.base.service.framework.utils.QiniuUtils;
import cn.huiyunche.base.service.interfaces.*;
import cn.huiyunche.base.service.mappers.*;
import cn.huiyunche.base.service.mappers.ext.CBalanceViewMapper;
import cn.huiyunche.base.service.mappers.ext.CBillOrdersViewMapper;
import cn.huiyunche.base.service.mappers.ext.CBillViewMapper;
import cn.huiyunche.base.service.model.*;
import cn.huiyunche.base.service.model.view.CBillOrdersViewExample;
import cn.huiyunche.base.service.utils.DateUtils;
import cn.huiyunche.base.service.utils.ExcelExport;
import cn.huiyunche.base.service.utils.JavaSmsApi;
import cn.huiyunche.base.service.vo.*;
import cn.huiyunche.tools.basic.exceptions.BusinessException;
import com.alibaba.fastjson.JSON;
import io.jsonwebtoken.lang.Collections;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 账单接口实现类
 *
 * @author lm
 */
@Service
public class CAccntBillServiceImpl implements CAccntBillService {

    private static final Logger LOGGER = LoggerFactory.getLogger(CAccntBillServiceImpl.class);

    @Autowired
    private CBillMapper cBillMapper = null;

    @Autowired
    private CBillViewMapper cBillViewMapper = null;

    @Autowired
    private CAccntBalanceService cAccntBalanceService = null;

    @Autowired
    private CAccntTurnOverService cAccntTurnOverService = null;

    @Autowired
    private CBalanceViewMapper cBalanceViewMapper = null;

    @Autowired
    private CBillOrdersViewMapper cBillOrdersViewMapper = null;

    @Autowired
    private UserService userService = null;

    @Autowired
    private BScoresService bScoresService = null;

    @Autowired
    private CTurnoverMapper cTurnoverMapper = null;

    @Autowired
    private SOrderMapper sOrderMapper = null;

    @Autowired
    private CWaybillMapper cWaybillMapper = null;

    @Autowired
    private BCompanyUserService bCompanyUserService = null;

    @Autowired
    private SendMessageService sendMessageService = null;

    @Autowired
    private BFilesService bFilesService = null;

    @Autowired
    private CBillTypeMapper cBillTypeMapper = null;

    private CBillTypeMapper getCBillTypeMapper() {
        return this.cBillTypeMapper;
    }

    private BFilesService getBFilesService() {
        return this.bFilesService;
    }

    private SendMessageService getSendMessageService() {
        return this.sendMessageService;
    }

    private BCompanyUserService getBCompanyUserService() {
        return this.bCompanyUserService;
    }

    private CWaybillMapper getCWaybillMapper() {
        return this.cWaybillMapper;
    }

    private SOrderMapper getSOrderMapper() {
        return sOrderMapper;
    }

    private CTurnoverMapper getCTurnoverMapper() {
        return this.cTurnoverMapper;
    }

    private BScoresService getBScoresService() {
        return this.bScoresService;
    }

    private CBillMapper getCBillMapper() {
        return this.cBillMapper;
    }

    private CAccntBalanceService getCAccntBalanceService() {
        return this.cAccntBalanceService;
    }

    private CAccntTurnOverService getCAccntTurnOverService() {
        return this.cAccntTurnOverService;
    }

    private CBillViewMapper getcBillViewMapper() {
        return cBillViewMapper;
    }

    private CBalanceViewMapper getcBalanceViewMapper() {
        return this.cBalanceViewMapper;
    }

    private CBillOrdersViewMapper getCBillOrdersViewMapper() {
        return this.cBillOrdersViewMapper;
    }

    private UserService getUserService() {
        return this.userService;
    }

    // 查询当前登录用户
    public UserShowVo getUserShowVo() {
        try {
            return this.getUserService().getCurrentUser();
        } catch (Exception e) {
            LOGGER.error("select current user ERROR : {}.", e);
            throw new BusinessException("查询当前登录用户异常");
        }
    }

    /**
     * 生成托运企业 - 个人 月账单
     * 月对账使用 包含：发车的每一单的 实际金额
     *
     * @param beginDate 2016-07-01 00:00:00
     * @param endDate   2016-08-01 00:00:00
     * @param redo      是否重新结算
     * @param userId    公司账户ID
     * @param userType  账户类型：托运企业
     * @param userIdSet 用户ID set集合(去除非自然月出账单的托运企业)
     * @return
     */
    @Override
    public boolean genKyleMonthBill(Date beginDate, Date endDate, boolean redo, Long userId, int userType, Set<Long> userIdSet) {
        LOGGER.info("gen kyle company month bill params : beginDate:{}, endDate:{}, redo:{}, userId:{}, userType:{}, userIdSet:{}.",
                beginDate, endDate, redo, userId, userType, userIdSet);
        boolean result = false;
        try {
            if (true == redo) {
                List<CBill> billList = this.getcBillViewMapper().selectByTimeNoUser(beginDate, endDate, userId, userType, userIdSet);
                List<Long> ids = new ArrayList<Long>();
                for (CBill accntBill : billList) {
                    ids.add(accntBill.getId());

                    CTurnoverExample turnoverExample = new CTurnoverExample();
                    turnoverExample.createCriteria().andBillIdEqualTo(accntBill.getId());
                    CTurnover turnover = new CTurnover();
                    turnover.setStatus(AccTurnoverStatusEnum.WAIT.getValue());
                    cTurnoverMapper.updateByExampleSelective(turnover, turnoverExample);
                }

                if (ids.size() > 0) {
                    int delectCount = this.getcBillViewMapper().deleteByIds(ids);
                    LOGGER.info("gen driver month bill redo delete {} nums.", delectCount);
                }
            }
            // 托运企业 结算只有订单业务类型
            List<Integer> payTypes = new ArrayList<Integer>();
            payTypes.add(AccPaytypeEnum.ORDER.getValue());

            int billStatus = AccBillStatusEnum.WAIT.getValue(); // 托运企业账单 初始化账单 “结算申请”
            // 查询订单流水中 userType=40类型的 记录 生成账单 根据账户ID分组
            this.getcBillViewMapper().genCompanyBill(beginDate, endDate, userId, userType, payTypes, billStatus);
            // this.getcBillViewMapper().genkyleCompanyBill(beginDate, endDate, userId, userType, payTypes, billStatus);
            LOGGER.info("gen kyle month bill finish.");

            // 更新流水中的状态 将账单ID billid插入到账单流水中
            int status = AccTurnoverStatusEnum.BILL.getValue();
            int count = this.getCAccntTurnOverService().updateBnoByCompanyBillid(beginDate, endDate, userId, userType, payTypes, status);
            LOGGER.info("gen kyle month bill bill update details {} nums.", count);

            result = true;
        } catch (Exception e) {
            LOGGER.error("gen driver month bill error : {}.", e);
            e.printStackTrace();
        }
        return result;
    }
    /** @Override public boolean genKyleMonthBill(Date beginDate, Date endDate, boolean redo, Long userId, int userType, Set<Long> userIdSet) {
    LOGGER.info("gen kyle company month bill params : beginDate:{}, endDate:{}, redo:{}, userId:{}, userType:{}, userIdSet:{}.",
    beginDate, endDate, redo, userId, userType, userIdSet);
    boolean result = false;
    try {
    if(true == redo){
    List<CBill> billList = this.getcBillViewMapper().selectByTimeNoUser(beginDate, endDate, userId, userType, userIdSet);
    List<Long> ids = new ArrayList<Long>();
    for (CBill accntBill : billList) {
    ids.add(accntBill.getId());

    CTurnoverExample turnoverExample = new CTurnoverExample();
    turnoverExample.createCriteria().andBillIdEqualTo(accntBill.getId());
    CTurnover turnover = new CTurnover();
    turnover.setStatus(AccTurnoverStatusEnum.WAIT.getValue());
    cTurnoverMapper.updateByExampleSelective(turnover, turnoverExample);
    }

    if(ids.size() > 0){
    int delectCount = this.getcBillViewMapper().deleteByIds(ids);
    LOGGER.info("gen driver month bill redo delete {} nums.", delectCount);
    }
    }
    // 托运企业 结算只有订单业务类型
    List<Integer> payTypes = new ArrayList<Integer>();
    payTypes.add(AccPaytypeEnum.ORDER.getValue());

    int billStatus = AccBillStatusEnum.WAIT.getValue(); // 托运企业账单 初始化账单 “结算申请”
    // 查询订单流水中 userType=20/40类型的 记录 生成账单 根据账户ID分组
    // this.getcBillViewMapper().genMonthBillNoUser(beginDate, endDate, userId, userType, payTypes, userIdSet);
    this.getcBillViewMapper().genCompanyBill(beginDate, endDate, userId, userType, payTypes, billStatus);
    LOGGER.info("gen kyle month bill finish.");
    // this.getcBillViewMapper().genMonthBillNoUser(beginDate, endDate, userId, userType, payTypes, userIdSet);
    // LOGGER.info("gen driver month bill finish.");

    // 更新流水中的状态 将账单ID billid插入到账单流水中
    int status = AccTurnoverStatusEnum.BILL.getValue();
    // int count = this.getCAccntTurnOverService().updateBnoByBillidNoUser(beginDate, endDate, userId, userType, payTypes, userIdSet, status);
    int count = this.getCAccntTurnOverService().updateBnoByCompanyBillid(beginDate, endDate, userId, userType, payTypes, status);
    LOGGER.info("gen kyle month bill bill update details {} nums.", count);
    // int count = this.getCAccntTurnOverService().updateBnoByBillidNoUser(beginDate, endDate, userId, userType, payTypes, userIdSet, status);
    // LOGGER.info("gen driver month bill bill update details {} nums.", count);

    result = true;
    } catch (Exception e) {
    LOGGER.error("gen driver month bill error : {}.", e);
    e.printStackTrace();
    }
    return result;
    } */

    /**
     * 生成物流企业 月账单
     * 月对账使用 包含：邀请司机注册的费用20 和 未支付给企业的运输费用
     *
     * @param beginDate 2016-07-01 00:00:00
     * @param endDate   2016-08-01 00:00:00
     * @param redo      是否重新结算
     * @param userId    公司账户ID == 公司ID
     * @param userType  账户类型：运输公司
     * @return
     */
    @Override
    public boolean genStanCompanyMonthBill(Date beginDate, Date endDate, boolean redo, Long userId, int userType) {
        LOGGER.info("gen stan company month bill params : beginDate:{}, endDate:{}, redo:{}, userId:{}, userType:{}.",
                beginDate, endDate, redo, userId, userType);
        boolean result = false;
        try {
            if (true == redo) {
                List<CBill> billList = this.getcBillViewMapper().selectByTime(beginDate, endDate, userId, userType, null);
                List<Long> ids = new ArrayList<Long>();
                for (CBill accntBill : billList) {
                    ids.add(accntBill.getId());
                }

                if (!Collections.isEmpty(ids)) {
                    int delectCount = this.getcBillViewMapper().deleteByIds(ids);
                    LOGGER.info("gen stan company month bill redo delete {} nums.", delectCount);
                }
            }
            List<Integer> payTypes = new ArrayList<Integer>();
            payTypes.add(AccPaytypeEnum.ORDER.getValue());
            payTypes.add(AccPaytypeEnum.REGISTER.getValue());

            int status = AccBillStatusEnum.SETTLTMENT.getValue(); // 物流企业账单 初始化账单 “结算申请”
            // 查询订单流水中 userType=30类型的 记录 生成账单 根据账户ID分组
            // this.getcBillViewMapper().genMonthBill(beginDate, endDate, userId, userType, payTypes, null, status);
            this.getcBillViewMapper().genCompanyBill(beginDate, endDate, userId, userType, payTypes, status);
            LOGGER.info("gen stan company month bill finish.");

            // 更新流水中的状态 将账单ID billid插入到账单流水中
            int turnoverStatus = AccTurnoverStatusEnum.BILL.getValue();
            // int count = this.getCAccntTurnOverService().updateBnoByBillid(beginDate, endDate, userId, userType, payTypes, null, turnoverStatus);
            int count = this.getCAccntTurnOverService().updateBnoByCompanyBillid(beginDate, endDate, userId, userType, payTypes, turnoverStatus);
            LOGGER.info("gen stan company month bill update details {} nums.", count);

            result = true;
        } catch (Exception e) {
            LOGGER.error("gen stan company month bill error : {}.", e);
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 生成周账单, 只生成司机的账单
     * 并且增加 账户余额表中可提现金额
     *
     * @param beginDate     2016-08-15 00:00:00
     * @param endDate       2016-08-22 00:00:00
     * @param updateBalance 是否更新余额(更新账户表可提现金额)
     * @param redo          是否是重新结算
     * @param userId        司机账户ID
     * @param userType      账户类型：司机账户
     */
    @Override
    public boolean genMonthBill(Date beginDate, Date endDate, Boolean updateBalance, Boolean redo, Long userId, int userType) {
        LOGGER.info("AccntBillServiceImpl : genMonthBill : beginDate:{}, endDate:{}, updateBalance:{}, redo:{}, userId:{}, userType:{}.",
                beginDate, endDate, updateBalance, redo, userId, userType);
        boolean result = false;
        try {
            if (true == redo) {
                // 重新结算
                // 查询账单 beginDate-endDate 删除账单 并将可提现金额 更新(扣除账单金额)
                List<CBill> billList = this.getcBillViewMapper().selectByTime(beginDate, endDate, userId, userType, null);
                List<Long> ids = new ArrayList<Long>();
                for (CBill accntBill : billList) {
                    BigDecimal amount = accntBill.getAmount();
                    LOGGER.info("gen driver week bill delete existed bill whihdrawBalance params userId:{}, userType:{}, amount:{}.", userId, userType, amount);

                    CBalance cBalance = this.getCAccntBalanceService().getAccntLedger(accntBill.getUserId(), userType);
                    if (null == cBalance) {
                        continue;
                    }
                    cBalance.setWithdrawalBalance(amount.abs().negate());
                    cBalance.setBalance(null);

                    this.getCAccntBalanceService().insertOrUpdateRecord(cBalance);
                    ids.add(accntBill.getId());
                }

                if (!Collections.isEmpty(ids)) {
                    int delectCount = this.getcBillViewMapper().deleteByIds(ids);
                    LOGGER.info("重新结算删除账单 {} 条记录.", delectCount);
                }

                // this.updateLedgerWBalance(beginDate, endDate, userId, userType, true);

                // int deleteCount = this.getcBillViewMapper().deleteByTime(beginDate, endDate, userId, userType);
                // log.info("生成月账单，重新结算删除数据 {} 条.", deleteCount);
            }
            // 司机生成账单 业务类型：订单 注册奖励  人为奖 罚
            List<Integer> payTypes = new ArrayList<Integer>();
            payTypes.add(AccPaytypeEnum.ORDER.getValue());
            payTypes.add(AccPaytypeEnum.REGISTER.getValue());
            payTypes.add(AccPaytypeEnum.REWARD.getValue());
            payTypes.add(AccPaytypeEnum.PUNISH.getValue());

            int status = AccBillStatusEnum.WAIT.getValue(); // 司机账单 进来就是已完成/需要线下审核 改为生成账单状态
            this.getcBillViewMapper().genMonthBill(beginDate, endDate, userId, userType, payTypes, null, status);
            LOGGER.info("生成司机月账单插入bill表完成.");

            // 更新司机可提现金额
            this.updateLedgerWBalance(beginDate, endDate, userId, userType, false);

            // 更新流水明细
            int count = this.getCAccntTurnOverService().updateBnoByBillid(beginDate, endDate, userId, userType, payTypes, null, 0);
            LOGGER.info("生成账单，更新明细数据 {} 条.", count);

            result = true;
        } catch (Exception e) {
            LOGGER.error("生成月账单异常.", e);
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 更新－司机－账户余额表 可提现金额
     *
     * @param beginDate // 2016-07-01 00：00：00
     * @param endDate   // 2016-08-01 00：00：00
     * @param userId    // 用户ID
     * @param userType  // 用户类型
     * @param flag      // true 取负数 扣除可提现金额	false 账单金额
     */
    private void updateLedgerWBalance(Date beginDate, Date endDate, Long userId, int userType, boolean flag) {
        // === 查询endDate - 2 2个月之前的订单, 将账单金额添加到账户余额表 可提现金额中
        // 最新需求 每月10号提现 ...本月1号之前的所有金额 可以提现
        // Date beginDate_Before2 = DateUtils.addMonths(beginDate, -2);
        // Date endDate_Before2 = DateUtils.addMonths(endDate, -2);

        try {
            List<CBill> billList = this.getcBillViewMapper().selectByTime(beginDate, endDate, userId, userType, null);
            for (CBill accntBill : billList) {
                BigDecimal amount = accntBill.getAmount();
                LOGGER.info("gen driver week bill to update withdrawBalance params accid:{}, acctype:{}, amount:{}.", userId, userType, amount);

                CBalance cBalance = this.getcBalanceViewMapper().selectByIdAndUsertype(userId, userType);
                if (cBalance == null) {
                    cBalance = new CBalance();
                }
                // CBalance cBalance = new CBalance();
                cBalance.setUserId(accntBill.getUserId());
                cBalance.setUserName(accntBill.getUserName());
                cBalance.setUserType(accntBill.getUserType());
                cBalance.setCreateTime(new Date());
                cBalance.setBalance(null);

                // 重新结算 可提现金额要扣除 所以balance取负
                if (accntBill.getUserType() == UserTypeEnum.DRIVER.getValue() || accntBill.getUserType() == UserTypeEnum.SEND_DRIVER.getValue()) {
                    if (flag) {
                        cBalance.setWithdrawalBalance(cBalance.getWithdrawalBalance().add(amount.negate()));
                    } else {
                        cBalance.setWithdrawalBalance(amount.abs());
                    }
                }
                LOGGER.info("gen driver week bill to update withdrawBalance insertOrUpdateRecord : {}.", JSON.toJSONString(cBalance));
                this.getCAccntBalanceService().insertOrUpdateRecord(cBalance);
            }
        } catch (Exception e) {
            LOGGER.error("gen driver week bill to update withdrawBalance error : {}.", e);
            e.printStackTrace();
        }
        LOGGER.info("gen driver week bill to update withdrawBalance finish.");
    }

    /**
     * 查询账单记录
     * page
     * userType
     */
    @Override
    public Map<String, Object> getBills(PageVo page, CBillAdminVo bill, int userType) {
        LOGGER.info("select bills params page:{}, userType:{}.", page, userType);
        Map<String, Object> map = new HashMap<String, Object>();
        try {
            Map<String, Object> paramsMap = new HashMap<>();
            paramsMap.put("limitStart", page.getStartIndex());
            paramsMap.put("limitEnd", page.getPageSize());
            if (StringUtils.isNotBlank(page.getOrder())) {
                paramsMap.put("orderByClause", page.getOrder());
            } else {
                paramsMap.put("orderByClause", " id DESC");
            }

            if (null != bill) {
                paramsMap.put("userType", bill.getUserType());
                paramsMap.put("userName", bill.getUserName());
                paramsMap.put("phone", bill.getPhone());
                paramsMap.put("status", bill.getStatus());
                //	paramsMap.put("beginDate", bill.getBeginDate());
                //	paramsMap.put("endDate", bill.getEndDate());
                String beginDateParam = bill.getBeginDateParam();
                if (StringUtils.isNotBlank(beginDateParam)) {
                    paramsMap.put("beginDate", DateUtils.StrToDate(bill.getBeginDateParam(), DateUtils.FORMAT_DATETIME));
                }
                String endDateParam = bill.getEndDateParam();
                if (StringUtils.isNotBlank(endDateParam)) {
                    paramsMap.put("endDate", DateUtils.StrToDate(bill.getEndDateParam(), DateUtils.FORMAT_DATETIME));
                }
            }

            page.setTotalRecord(this.getcBillViewMapper().countByConditions(paramsMap));
            List<CBillAdminVo> list = this.getcBillViewMapper().selectByConditions(paramsMap);

            map.put("page", page);
            map.put("cBills", list);
            /** List<CBill> cBills = new ArrayList<CBill>();

             CBillExample example = new CBillExample();
             example.setLimitStart(page.getStartIndex());
             example.setLimitEnd(page.getPageSize());
             if(StringUtils.isNotBlank(example.getOrderByClause())){
             example.setOrderByClause(example.getOrderByClause());
             } else{
             example.setOrderByClause("id DESC");
             }
             example.createCriteria().andUserTypeEqualTo(userType);

             page.setTotalRecord(this.getCBillMapper().countByExample(example));
             cBills = this.getCBillMapper().selectByExample(example);

             LOGGER.info("select bills finish. params userType:{}.", userType);
             map.put("cBills", cBills);
             map.put("page", page); */
        } catch (Exception e) {
            LOGGER.error("select bills error : {}.", e);
            e.printStackTrace();
        }
        return map;
    }

    /**
     * 根据当前用户 查询该用户所有账单
     * ＋ 本月车辆数
     * ＋ 本月订单数
     * ＋ 未支付金额(部分付款)
     *
     * @return
     */
    @Override
    public List<CBillOrdersVo> getBillsAddOrders(Integer billType) {
        LOGGER.info("get bills by current user");
        List<CBillOrdersVo> cBillOrdersVos = new ArrayList<>();
        try {
            // 查询当前用户
            UserShowVo userShowVo = this.getUserShowVo();
            LOGGER.info("select current user userShowVo : {}.", JSON.toJSONString(userShowVo));
            if (null == userShowVo) {
                LOGGER.info("select current user is not exist userShowVo : {}.", JSON.toJSONString(userShowVo));
                throw new BusinessException("当前登录账户不存在");
            }

            CBillOrdersViewExample example = new CBillOrdersViewExample();
            example.setOrderByClause(" b.begin_date DESC");
            Integer userType = userShowVo.getUserType();
            long userId = userShowVo.getId();
            if (userType == UserTypeEnum.COMPANY.getValue() || userType == UserTypeEnum.SCOMPANY.getValue()) {
                userId = this.getBCompanyUserService().getCompanyIdByUserId(userId);
            }
            if (billType != null) {
                example.createCriteria().andUserIdEqualTo(userId).andUserTypeEqualTo(userType).andBillTypeEqualTo(billType);
            } else {
                example.createCriteria().andUserIdEqualTo(userId).andUserTypeEqualTo(userType);
            }
            if (userType == UserTypeEnum.COMPANY.getValue()) {
                cBillOrdersVos = this.getCBillOrdersViewMapper().selectStanBussBills(example);
            } else {
                cBillOrdersVos = this.getCBillOrdersViewMapper().selectByExample(example);
            }
            if (!Collections.isEmpty(cBillOrdersVos)) {
                return cBillOrdersVos;
            } else {
                CBillOrdersVo vo = new CBillOrdersVo();
                vo.setId(0L);
                vo.setAmount(BigDecimal.ZERO);
                vo.setEndDate(DateUtils.firstDayOfLastMonth(new Date()));
                vo.setOrderAmount(0);
                vo.setCarAmount(0);
                vo.setStatus(AccBillStatusEnum.DONE.getValue());
                vo.setScoresPaid(BigDecimal.ZERO);

                cBillOrdersVos.add(vo);
                return cBillOrdersVos;
            }
        } catch (Exception e) {
            LOGGER.error("get bills by current user error : {}.", e);
            throw new BusinessException("根据当前用户查询账单异常");
        }
    }

    /**
     * 根据当前用户 查询该用户所有账单
     * ＋ 本月车辆数
     * ＋ 本月订单数
     * ＋ 未支付金额(部分付款)
     *
     * @return
     */
    @Override
    public Map<String, Object> getTotalBillsAddOrders() {
        LOGGER.info("get bills by current user");
        Map<String, Object> map = new HashMap<>();
        try {
            // 查询当前用户
            UserShowVo userShowVo = this.getUserShowVo();
            LOGGER.info("select current user userShowVo : {}.", JSON.toJSONString(userShowVo));
            if (null == userShowVo) {
                LOGGER.info("select current user is not exist userShowVo : {}.", JSON.toJSONString(userShowVo));
                throw new BusinessException("当前登录账户不存在");
            }

            CBillOrdersViewExample example = new CBillOrdersViewExample();
            example.setOrderByClause(" b.begin_date DESC");
            Integer userType = userShowVo.getUserType();
            long userId = userShowVo.getId();
            if (userType == UserTypeEnum.COMPANY.getValue() || userType == UserTypeEnum.SCOMPANY.getValue()) {
                userId = this.getBCompanyUserService().getCompanyIdByUserId(userId);
            }
            example.createCriteria().andUserIdEqualTo(userId).andUserTypeEqualTo(userType);
            List<CBillOrdersVo> cBillOrdersVos = this.getCBillOrdersViewMapper().selectByExample(example);
            cBillOrdersVos = this.buildDate(cBillOrdersVos);
            if (!Collections.isEmpty(cBillOrdersVos)) {
                map.put("cBillOrdersVos", cBillOrdersVos);
                map.put("billTypes", this.getCBillType());
                return map;
            } else {
                CBillOrdersVo vo = new CBillOrdersVo();
                vo.setId(0L);
                vo.setAmount(BigDecimal.ZERO);
                vo.setEndDate(DateUtils.firstDayOfLastMonth(new Date()));
                vo.setOrderAmount(0);
                vo.setCarAmount(0);
                vo.setStatus(AccBillStatusEnum.DONE.getValue());

                cBillOrdersVos.add(vo);
                map.put("cBillOrdersVos", cBillOrdersVos);
                map.put("billTypes", this.getCBillType());
                return map;
            }
        } catch (Exception e) {
            LOGGER.error("get bills by current user error : {}.", e);
            throw new BusinessException("根据当前用户查询账单异常");
        }
    }

    private List<CBillOrdersVo> buildDate(List<CBillOrdersVo> cBillOrdersVos) {
        Map<Object, Object> map = new HashMap<>();
        for (CBillOrdersVo cBillOrdersVo : cBillOrdersVos) {
            if (map.containsKey(cBillOrdersVo.getBeginDate())) {
                CBillOrdersVo cBillOrdersVoMap = (CBillOrdersVo) map.get(cBillOrdersVo.getBeginDate());
                cBillOrdersVo.setAmount(cBillOrdersVo.getAmount().add(cBillOrdersVoMap.getAmount()));
                cBillOrdersVo.setCarAmount(cBillOrdersVo.getCarAmount() + cBillOrdersVoMap.getCarAmount());
                cBillOrdersVo.setOrderAmount(cBillOrdersVo.getOrderAmount() + cBillOrdersVoMap.getOrderAmount());
                cBillOrdersVo.setScoresPaid(cBillOrdersVo.getScoresPaid() == null ? BigDecimal.ZERO : cBillOrdersVo.getScoresPaid().add(cBillOrdersVoMap.getScoresPaid()));
                map.put(cBillOrdersVo.getBeginDate(), cBillOrdersVo);
            } else {
                map.put(cBillOrdersVo.getBeginDate(), cBillOrdersVo);
            }
        }
        List<CBillOrdersVo> list = new ArrayList<>();
        for (Object in : map.keySet()) {
            list.add((CBillOrdersVo) map.get(in));
        }
        return list;
    }

    private List<CBillTypeVo> getCBillType() {
        CBillTypeExample cBillTypeExample = new CBillTypeExample();
        cBillTypeExample.createCriteria().andEnableEqualTo(true);
        List<CBillType> cBillTypes = this.getCBillTypeMapper().selectByExample(cBillTypeExample);
        List<CBillTypeVo> cBillTypeVos = new ArrayList<>();
        for (CBillType cBillType : cBillTypes) {
            CBillTypeVo cBillTypeVo = new CBillTypeVo();
            try {
                BeanUtils.copyProperties(cBillTypeVo, cBillType);
            } catch (Exception e) {
                LOGGER.error("copy model error: {}", e);
            }
            cBillTypeVo.setUrl(QiniuUtils.generateDownloadTicket(cBillType.getPic(), ""));
            cBillTypeVos.add(cBillTypeVo);
        }
        return cBillTypeVos;
    }

    /**
     * @Override public Map<String, Object> getBillScores(Long billId) {
     * CBill cBill = this.getCBillMapper().selectByPrimaryKey(billId);
     * <p>
     * Map<String, Object> map = new HashMap<>();
     * if(null == billId || 0 == billId || null == cBill){
     * QueryKyleBillScoresVo scoresVo = new QueryKyleBillScoresVo();
     * scoresVo.setActualPaid(BigDecimal.ZERO);
     * scoresVo.setAmount(BigDecimal.ZERO);
     * scoresVo.setBillstatus(AccBillStatusEnum.DONE.getValue());
     * scoresVo.setBillStatusShow(0);
     * scoresVo.setIsUserScores(0);
     * scoresVo.setScoresPaid(BigDecimal.ZERO);
     * scoresVo.setScoresText("积分抵扣金额¥0.00");
     * map.put("scoresVo", scoresVo);
     * <p>
     * map.put("billFiles", null);
     * return map;
     * }
     * <p>
     * // 查询可抵扣积分
     * QueryKyleBillScoresVo scoresVo = this.getScoresVo(billId);
     * if(cBill.getStatus() != AccBillStatusEnum.WAIT.getValue()){
     * scoresVo.setIsUserScores(1);
     * }
     * map.put("scoresVo", scoresVo);
     * map.put("billFiles", this.generateShareUrl4File(billId));
     * <p>
     * return map;
     * }
     */
    @Override
    public Map<String, Object> getBillScores(Long billId, Integer billType) {
        CBill cBill = this.getCBillMapper().selectByPrimaryKey(billId);

        Map<String, Object> map = new HashMap<>();
        if (null == billId || 0 == billId || null == cBill) {
            QueryKyleBillScoresVo scoresVo = new QueryKyleBillScoresVo();
            scoresVo.setActualPaid(BigDecimal.ZERO);
            scoresVo.setAmount(BigDecimal.ZERO);
            scoresVo.setBillstatus(AccBillStatusEnum.DONE.getValue());
            scoresVo.setBillStatusShow(0);
            scoresVo.setIsUserScores(0);
            scoresVo.setScoresPaid(BigDecimal.ZERO);
            scoresVo.setScoresText("积分抵扣金额¥0.00");
            map.put("scoresVo", scoresVo);

            map.put("billFiles", null);
            return map;
        }
        List<Long> billIds = this.getBillIds(billId);
        CBillExample example = new CBillExample();
        QueryKyleBillScoresVo scoresVo = new QueryKyleBillScoresVo();
        if (null != billType) {
            example.createCriteria().andIdIn(billIds).andBillTypeEqualTo(billType);
            List<CBill> list = this.getCBillMapper().selectByExample(example);
            if (CollectionUtils.isNotEmpty(list)) {
                billId = list.get(0).getId();
                // 查询可抵扣积分
                scoresVo = this.getScoresVo(billId);
            }
        } else {
            BigDecimal totalAmunt = BigDecimal.ZERO;
            if (CollectionUtils.isNotEmpty(billIds)) {
                for (int k = 0; k < billIds.size(); k++) {
                    scoresVo = this.getScoresVo(billIds.get(k));
                    totalAmunt = totalAmunt.add(scoresVo.getActualPaid());
                }

            }
            scoresVo.setActualPaid(totalAmunt);
        }

        if (cBill.getStatus() != AccBillStatusEnum.WAIT.getValue()) {
            scoresVo.setIsUserScores(1);
        }
        map.put("scoresVo", scoresVo);
        map.put("billFiles", this.generateShareUrl4File(billId));

        return map;
    }

    private List<Long> getBillIds(Long billId) {
        CBill cBill = this.getCBillMapper().selectByPrimaryKey(billId);
        Long userId = cBill.getUserId();
        Integer userType = cBill.getUserType();
        Date beginDate = cBill.getBeginDate();
        CBillExample example = new CBillExample();
        example.createCriteria().andUserIdEqualTo(userId).andUserTypeEqualTo(userType).andBeginDateEqualTo(beginDate);
        List<CBill> list = this.getCBillMapper().selectByExample(example);
        List<Long> billIds = new ArrayList<>();
        for (CBill cBillNew : list) {
            billIds.add(cBillNew.getId());
        }
        return billIds;
    }

    @Override
    public Map<String, Object> getAppBillDetails(PageVo page, Long billId) {
        Map<String, Object> map = new HashMap<>();
        if (null == billId || 0 == billId) {
            List<CTurnoverOrdersVo> cTurnovers = new ArrayList<CTurnoverOrdersVo>();
            map.put("cTurnovers", cTurnovers);
        } else {
            List<Long> billIds = this.getBillIds(billId);
            map = this.getCAccntTurnOverService().getKyleBussDetails(page, billIds);
            QueryKyleBillScoresVo scoresVo = this.getScoresVo(billId);
            map.put("scoresVo", scoresVo);
        }
        return map;
    }

    @Override
    public BigDecimal getScoresUserdAmount(Long billId) {
        List<Long> billIds = this.getBillIds(billId);
        BigDecimal userdAmount = BigDecimal.ZERO;
        for (Long id : billIds) {
            CBill newBill = this.getCBillMapper().selectByPrimaryKey(id);
            if (null != newBill) {
                userdAmount = userdAmount.add(newBill.getScoresPaid() == null ? BigDecimal.ZERO : newBill.getScoresPaid());
            }
        }
        return userdAmount;
    }

    private QueryKyleBillScoresVo getScoresVo(Long billId) {
        // 查询明细的时候 查询本月账单可用积分抵扣金额
        QueryKyleBillScoresVo scoresVo = new QueryKyleBillScoresVo();
        int billStatus = 0;
        if (billId != null && billId != 0L) {
            CBill cBill = this.selectByPrimaryKey(billId);
            if (cBill != null) {
                scoresVo = this.getBScoresService().selectKyleCompanyBillScores(cBill.getAmount().abs(), this.getScoresUserdAmount(billId));
                billStatus = cBill.getStatus();
                if (billStatus == AccBillStatusEnum.WAIT.getValue()) {
                    scoresVo.setBillStatusShow(1);
                } else {
                    scoresVo.setBillStatusShow(0);
                }

                BigDecimal scoresPaid = cBill.getScoresPaid();
                if (null == scoresPaid) {
                    scoresPaid = BigDecimal.ZERO;
                }
                if (scoresPaid.compareTo(BigDecimal.ZERO) == 1) {
                    scoresVo.setIsUserScores(1);
                } else {
                    scoresVo.setIsUserScores(0);
                }
                scoresVo.setScoresPaid(scoresPaid);
                scoresVo.setActualPaid(cBill.getAmount().abs().subtract(scoresPaid.abs()).setScale(2, BigDecimal.ROUND_UP));
            }
        } else {
            scoresVo.setIsUserScores(0);
        }

        if (0 != billStatus) {
            scoresVo.setBillstatus(billStatus);
        } else {
            scoresVo.setBillstatus(AccBillStatusEnum.WAIT.getValue());
        }

        return scoresVo;
    }

    /**
     * 根据账单ID 查询账单明细
     *
     * @param billId
     * @return
     */
    @Override
    public Map<String, Object> getBillDetails(PageVo page, Long billId) {
        LOGGER.info("select details by billId params billId : {}.", billId);
        try {
            CTurnover cTurnover = new CTurnover();
            cTurnover.setBillId(billId);

            CBill cBill = this.getCBillMapper().selectByPrimaryKey(billId);

            Map<String, Object> map = new HashMap<>();
            if (null == billId || 0 == billId || null == cBill) {
                map.put("page", page);

                List<CTurnoverOrdersVo> cTurnovers = new ArrayList<CTurnoverOrdersVo>();
                map.put("cTurnovers", cTurnovers);

                QueryKyleBillScoresVo scoresVo = new QueryKyleBillScoresVo();
                scoresVo.setActualPaid(BigDecimal.ZERO);
                scoresVo.setAmount(BigDecimal.ZERO);
                scoresVo.setBillstatus(AccBillStatusEnum.DONE.getValue());
                scoresVo.setBillStatusShow(0);
                scoresVo.setIsUserScores(0);
                scoresVo.setScoresPaid(BigDecimal.ZERO);
                scoresVo.setScoresText("积分抵扣金额¥0.00");
                map.put("scoresVo", scoresVo);

                map.put("billFiles", null);

                return map;
            }
            BigDecimal scoresUserdAmount = this.getScoresUserdAmount(billId);
            Map<String, Object> details = this.getCAccntTurnOverService().getDetails(page, cTurnover, cBill.getAmount(), scoresUserdAmount, cBill.getStatus());
            details.put("billFiles", this.generateShareUrl4File(billId));
            QueryKyleBillScoresVo scoresVo = (QueryKyleBillScoresVo) details.get("scoresVo");
            if (cBill.getStatus() != AccBillStatusEnum.WAIT.getValue()) {
                scoresVo.setIsUserScores(1);
            }
            return details;
        } catch (Exception e) {
            LOGGER.error("select details by billId params billId : {}, error : {}.", billId, e);
            throw new BusinessException("根据账单ID查询明细异常");
        }
    }

    /**
     * 根据用户ID 用户类型  查询用户最后一个月账单
     * －－ 托运企业 首页显示
     *
     * @param userId
     * @param userType
     * @return
     */
    @Override
    public CBill getLastMonthBill(Long userId, int userType) {
        LOGGER.info("select user last month bill by userId : {}, userType : {}.", userId, userType);
        try {
            CBillExample example = new CBillExample();
            example.setOrderByClause(" begin_date DESC");
            example.setLimitStart(0);
            example.setLimitEnd(1);
            // example.createCriteria().andUserIdEqualTo(userId).andUserTypeEqualTo(userType);
            if (userType == UserTypeEnum.COMPANY.getValue() || userType == UserTypeEnum.SCOMPANY.getValue()) {
                userId = this.getBCompanyUserService().getCompanyIdByUserId(userId);
            }
            example.createCriteria().andUserIdEqualTo(userId).andUserTypeEqualTo(userType);
            List<CBill> cbill = this.getCBillMapper().selectByExample(example);
            if (!Collections.isEmpty(cbill)) {
                BigDecimal amount = cbill.get(0).getAmount();
                cbill.get(0).setAmount(amount.abs());
                return cbill.get(0);
            }
        } catch (Exception e) {
            LOGGER.error("select user last month bill by userId : {}, userType : {}, error : {}.", userId, userType, e);
            throw new BusinessException("查询用户最后一个月账单异常");
        }
        return null;
    }

    /**
     * 托运企业 月账单结算的时候 使用积分
     * 扣除积分
     *
     * @param billId
     * @return
     */
    @Override
    public Result<String> kyleCompanyBillUserScores(Long billId) {
        LOGGER.info("driver company month bill user scores params billId : {}.", billId);
        try {
            return this.getBScoresService().kyleCompanyBillUserScores(billId);
        } catch (Exception e) {
            LOGGER.error("driver company month bill user scores params billId : {}, error : {}.", billId, e);
            throw new BusinessException("托运企业月结算扣除积分异常");
        }
    }

    /**
     * 根据主键查询账单
     *
     * @param billId
     * @return
     */
    @Override
    public CBill selectByPrimaryKey(Long billId) {
        try {
            return this.getCBillMapper().selectByPrimaryKey(billId);
        } catch (Exception e) {
            LOGGER.error("select cbill by id error : {}.", e);
            throw new BusinessException("根据主键查询账单异常");
        }
    }

    @Override
    public int updateBillStatus(Long billId) {
        LOGGER.info("updateBillStatus params billId: {}", billId);
        if (billId == null) {
            LOGGER.info("billId is not null");
            throw new BusinessException("账单ID不能为空");
        }
        // 更新账单状态
        CBill cBill = new CBill();
        cBill.setId(billId);
        cBill.setStatus(AccBillStatusEnum.DONE.getValue());
        this.getCBillMapper().updateByPrimaryKeySelective(cBill);
        // 更新账单明细状态
        CTurnoverExample example = new CTurnoverExample();
        example.createCriteria().andBillIdEqualTo(billId);
        List<CTurnover> cTurnovers = this.getCTurnoverMapper().selectByExample(example);
        if (!Collections.isEmpty(cTurnovers)) {
            for (CTurnover cTurnover : cTurnovers) {
                cTurnover.setStatus(AccBillStatusEnum.DONE.getValue());
                this.getCTurnoverMapper().updateByPrimaryKeySelective(cTurnover);
                // 更新订单支付状态 或运单支付状态
                if (cTurnover.getUserType() == UserTypeEnum.SCOMPANY.getValue()) {
                    if (cTurnover.getPayType() == AccPaytypeEnum.ORDER.getValue()) {
                        SOrder sOrder = new SOrder();
                        sOrder.setId(cTurnover.getOrderId());
                        sOrder.setPayStatus(PaymentStatusEnum.ALREADY_PAID.getValue());
                        this.getSOrderMapper().updateByPrimaryKeySelective(sOrder);
                    }
                } else if (cTurnover.getUserType() == UserTypeEnum.COMPANY.getValue()) {
                    if (cTurnover.getPayType() == AccPaytypeEnum.ORDER.getValue()) {
                        CWaybill cWaybill = new CWaybill();
                        cWaybill.setId(cTurnover.getOrderId());
                        cWaybill.setPayStatus(PaymentStatusEnum.ALREADY_PAID.getValue());
                        this.getCWaybillMapper().updateByPrimaryKeySelective(cWaybill);
                    }
                }
            }
        }
        return 0;
    }

    /**
     * 根据账单ID 更新积分抵扣金额
     *
     * @param cBill
     * @return
     */
    @Override
    public int updateByParimayKey(CBill cBill) {
        try {
            return this.getCBillMapper().updateByPrimaryKeySelective(cBill);
        } catch (Exception e) {
            LOGGER.error("update cbill by id error : {}.", e);
            throw new BusinessException("根据主键更新账单异常");
        }
    }

    /**
     * 托运公司 提交结算申请
     *
     * @param billId
     * @return
     */
    @Override
    public Result<String> kyleCompanySettlement(Long billId) {
        LOGGER.info("driver company settltment bill params billId : {}.", billId);
        Result<String> result = new Result<>(true, "申请结算完成");
        try {
            CBillExample example = new CBillExample();
            example.createCriteria().andIdEqualTo(billId).andStatusEqualTo(AccBillStatusEnum.WAIT.getValue());
            List<CBill> list = this.getCBillMapper().selectByExample(example);
            if (Collections.isEmpty(list) || list.get(0) == null) {
                result.setMessage("未查询到账单");
                return result;
            }
            list.get(0).setStatus(AccBillStatusEnum.SETTLTMENT.getValue());
            this.getCBillMapper().updateByPrimaryKeySelective(list.get(0));

            // 写入bFiles表
            this.addBFiles(billId);
        } catch (Exception e) {
            LOGGER.info("driver company settltment bill params billId : {}, error : {}.", billId, e);
            throw new BusinessException("托运公司提交结算申请异常");
        }
        return result;
    }

    @SuppressWarnings("unchecked")
    @Override
    public HSSFWorkbook generateExcel(Long billId) {
        LOGGER.info("generateExcel params billId : {}.", billId);
        try {
            // 商户生成的账单信息excel 上传服务器
            List<Long> billIds = this.getBillIds(billId);
            List<KyleCompanyBill> bills = this.getcBillViewMapper().selectkyleBillByBillId(billIds);

            List<String[]> listData10 = new ArrayList<String[]>();
            List<String[]> listData20 = new ArrayList<String[]>();
            String str[] = null;
            // "序号","订单日期","订单号","车型","托运数量","托运价格","托运总额","起运地","目的地","车架号","联系人","联系电话","承运日期","承运人","运单号",
            SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Map<String, Object> map = new HashMap<>();
            for (KyleCompanyBill bill : bills) {
                str = new String[14];
                str[0] = bill.getId().toString();
                str[1] = sf.format(bill.getCreateTime());
                str[2] = bill.getOrderCode();
                str[3] = bill.getVehicle();
                str[4] = bill.getVin();
                str[5] = bill.getWaybillName();
                str[6] = bill.getWaybillCode();
                str[7] = "1";// bill.getAmount()+"";
                str[8] = bill.getCost() + "";
                // str[6] = bill.getActualCost()+"";
                str[9] = bill.getDepartAddr();
                str[10] = bill.getReceiptAddr();
                str[11] = bill.getOrderName();
                str[12] = bill.getPhone();
                str[13] = sf.format(bill.getwCreateTime());
                if (bill.getIsVeneer()) {
                    listData10.add(str);
                    if (map.containsKey("同城账单")) {
                        listData10 = (List<String[]>) map.get("同城账单");
                        map.put("同城账单", listData10);
                    } else {
                        map.put("同城账单", listData10);
                    }
                } else {
                    listData20.add(str);
                    if (map.containsKey("城际账单")) {
                        listData20 = (List<String[]>) map.get("城际账单");
                        map.put("城际账单", listData20);
                    } else {
                        map.put("城际账单", listData20);
                    }
                }
            }

            // 表头名称
            String titleName = "发单明细";
            String[] titile = {"序号", "订单日期", "订单号", "车型", "车架号", "承运人", "运单号", "托运数量", "托运价格", "起运地", "目的地", "联系人", "联系电话", "承运日期",};
            Boolean[] isdigit = {null, null, null, null, null, null, null, null, null, null, null, null, null, null};
            int[] columnWidth = {20, 45, 60, 50, 30, 20, 60, 20, 20, 80, 80, 20, 30, 45};
            // HSSFWorkbook export = ExcelExport.export(fileName, titile, listData, columnWidth, isdigit, titleName);
            HSSFWorkbook export = ExcelExport.billExport(titile, columnWidth, isdigit, titleName, map);

            return export;
            // 写到服务器
            // write(export, fileName);
        } catch (Exception e) {
            LOGGER.info("generateExcel params billId : {}, error : {}.", billId, e);
            throw new BusinessException("商户账单申请结算，生成excel异常");
        }
    }

    private int addBFiles(Long billId) {
        LOGGER.error("add bFiles params billId : {}.", billId);
        try {
            CBill bill = this.getCBillMapper().selectByPrimaryKey(billId);
            String companyName = "";
            String year = "";
            String monthName = "";
            if (bill != null) {
                companyName = bill.getUserName();
                Date beginDate = bill.getEndDate();
                Calendar c = Calendar.getInstance();
                c.setTime(beginDate);
                year = c.get(Calendar.YEAR) + "年";
                monthName = c.get(Calendar.MONTH) + 1 + "月";
            }
            BFiles bFiles = new BFiles();
            bFiles.setBussId(billId);
            bFiles.setCreateTime(new Date());
            bFiles.setFileName(new Date().getTime() + "");
            bFiles.setSuffix("xls");
            bFiles.setRealName(companyName + monthName + "账单");
            bFiles.setDescription(year + monthName);
            return this.getBFilesService().add(bFiles);
        } catch (Exception e) {
            LOGGER.error("add bFiles params billId : {}, error : {}.", billId, e);
            throw new BusinessException("商户账单插入到bFiles数据异常");
        }
    }

    /**
     * private static void write(HSSFWorkbook wb, String fileName) throws IOException {
     * try {
     * String path = HYCUtils.getConstantPropertiesLoader().getProperty(App.KYLEBUSS_UPLOAD_ADDRESS) + fileName + ".xls";
     * File file = new File(path);
     * wb.write(file);
     * } catch (Exception e) {
     * e.printStackTrace();
     * } finally {
     * try {
     * wb.close();
     * } catch (IOException e) {
     * e.printStackTrace();
     * }
     * }
     * }
     */

    @Override
    public BigDecimal getSettlementAmount(Long billId) {
        LOGGER.info("select driver company settlement amount params billId : {}.", billId);
        try {
            CBill cBill = this.getCBillMapper().selectByPrimaryKey(billId);
            if (null == cBill) {
                LOGGER.info("select driver company settlement amount params billId : {} no bill.", billId);
                throw new BusinessException("结算账单不存在");
            }
            return cBill.getAmount().abs().subtract(cBill.getScoresPaid().abs()).setScale(2, BigDecimal.ROUND_UP);
        } catch (Exception e) {
            LOGGER.error("select driver company settlement amount params billId : {}, error : {}.", billId, e);
            throw new BusinessException("查询托运公司账单结算金额异常");
        }
    }

    @Override
    public Result<String> payBillFinish(Long billId) {
        LOGGER.info("pay bill finish params billId : {}.", billId);
        Result<String> result = new Result<>(true, "账单支付业务处理完成");
        try {
            CBill cBill = new CBill();
            cBill.setId(billId);
            cBill.setPayStatus(PaymentStatusEnum.ALREADY_PAID.getValue());
            this.getCBillMapper().updateByPrimaryKeySelective(cBill);
        } catch (Exception e) {
            LOGGER.error("pay bill finish params billId : {}, error : {}.", billId, e);
            throw new BusinessException("账单支付业务处理异常");
        }
        return result;
    }

    @Override
    public Map<String, Object> getVeneerBillDetails(PageVo page, Long billid) {
        LOGGER.info("select veneer bill params page : {}, billId : {}.", page, billid);
        try {
            return this.cAccntTurnOverService.selectVeneerDetails(page, billid);
        } catch (Exception e) {
            LOGGER.error("select veneer bill params page : {}, billId : {}, error : {}.", page, billid, e);
            throw new BusinessException("查询明细数据异常");
        }
    }

    /**
     * 人送项目司机 提现申请
     *
     * @param userId
     * @param userType
     * @return
     */
    @Override
    public Result<String> submitSettlementAppli(Long userId, Integer userType) {
        LOGGER.info("sendbydriver submit settlement applicate params userId : {}, userType : {}.", userId, userType);
        Result<String> result = new Result<>(true, "人送项目司机提现申请，修改账单状态完成");
        try {
            CBillExample example = new CBillExample();
            example.createCriteria().andUserIdEqualTo(userId).andUserTypeEqualTo(userType).andStatusEqualTo(AccBillStatusEnum.WAIT.getValue());
            List<CBill> bills = this.getCBillMapper().selectByExample(example);
            if (CollectionUtils.isNotEmpty(bills)) {
                for (CBill cBill : bills) {
                    cBill.setStatus(AccBillStatusEnum.SETTLTMENT.getValue());
                    int count = this.getCBillMapper().updateByPrimaryKeySelective(cBill);
                    LOGGER.info("sendbydriver submit settlement applicate params userId : {}, userType : {}, billid : {}, update count : {}.", userId, userType, count, cBill.getId());
                }
            }
        } catch (Exception e) {
            LOGGER.error("sendbydriver submit settlement applicate params userId : {}, userType : {}, error : {}.", userId, userType, e);
            throw new BusinessException("提交申请账单异常");
        }
        return result;
    }

    @Override
    public Result<String> settlementById(Long id) {
        Result<String> result = new Result<String>(true, null, "已支付，司机余额已扣除");
        try {
            // 查询账单 设置状态为 已支付
            CBill bill = this.getCBillMapper().selectByPrimaryKey(id);
            if (null == bill) {
                result.setSuccess(false);
                result.setMessage("未查询到账单");
                return result;
            } else if (bill.getStatus() != AccBillStatusEnum.SETTLTMENT.getValue()) {
                result.setSuccess(false);
                result.setMessage("该账单已结算，请务重复结算.");
                return result;
            }
            bill.setStatus(AccBillStatusEnum.DONE.getValue());
            this.getCBillMapper().updateByPrimaryKey(bill);

            // 添加账户流水记录 业务类型：提现 扣除金额
            List<CTurnover> list = new ArrayList<>();
            CTurnover cTurnover = new CTurnover();

            cTurnover.setPayType(AccPaytypeEnum.WITHDRAWAL.getValue());
            cTurnover.setStatus(AccTurnoverStatusEnum.DONE.getValue());
            cTurnover.setUserId(bill.getUserId());
            cTurnover.setUserName(bill.getUserName());
            cTurnover.setUserType(bill.getUserType());
            cTurnover.setOrderId(bill.getId());
            cTurnover.setOrderFee(bill.getAmount().abs().negate());
            cTurnover.setOrderActPay(bill.getAmount().abs().negate());
            cTurnover.setCreateTime(new Date());
            cTurnover.setUpdateTime(new Date());

            list.add(cTurnover);
            this.getCAccntTurnOverService().addDetailsAndLedger(list, 0);

            return result;
        } catch (Exception e) {
            LOGGER.error("settlement send by driver error : {}.", e);
            throw new BusinessException("系统异常");
        }
    }

    @Override
    public List<CBill> selectByExample(CBillExample billExample) {
        return this.getCBillMapper().selectByExample(billExample);
    }

    @Override
    public boolean genDriver3rdMonthBill(Date beginDate, Date endDate, Boolean redo, Long userId, Integer userType,
                                         Boolean updateBalance) {
        LOGGER.info(
                "gen driver 3rd month bill serviceimpl params beginDate:{}, endDate:{}, upudateBalance:{}, redo:{}, userId:{}.",
                beginDate, endDate, updateBalance, redo, userId);
        try {
            // 生成账单 更新明细
            this.genKyleMonthBill(beginDate, endDate, redo, userId, userType, null);

            return true;
        } catch (Exception e) {
            LOGGER.error(
                    "gen driver 3rd month bill serviceimpl params beginDate:{}, endDate:{}, upudateBalance:{}, redo:{}, userId:{}, error:{}.",
                    beginDate, endDate, updateBalance, redo, userId, e);
            throw new BusinessException("生成人送车队月账单异常");
        }
    }

    @Override
    public void sendBillMessage(Long userId, int userType, Date beginDate, Date endDate) {
        LOGGER.info("send bill message params userId : {}, userType : {}, beginDate : {}, endDate : {}.", userId, userType, beginDate, endDate);
        try {
            CBillExample example = new CBillExample();
            example.createCriteria().andUserTypeEqualTo(userType).andBeginDateEqualTo(beginDate).andEndDateLessThan(endDate);
            if (null != userId) {
                example.createCriteria().andUserIdEqualTo(userId);
            }
            List<CBill> bills = this.getCBillMapper().selectByExample(example);
            LOGGER.info("send bill message params userType : {}, beginDate : {}, endDate : {}, billSize : {}.", userType, beginDate, endDate, bills.size());
            if (CollectionUtils.isNotEmpty(bills)) {
                for (CBill cBill : bills) {
                    LOGGER.info("send bill message params userType : {}, beginDate : {}, endDate : {}, bill : {}.", userType, beginDate, endDate, cBill);
                    userId = cBill.getUserId();
                    List<BCompanyUser> userIds = this.getBCompanyUserService().getListByCompanyId(userId);

                    for (BCompanyUser bCompanyUser : userIds) {
                        Long userId2 = bCompanyUser.getUserId();
                        LOGGER.info("send bill message params userType : {}, beginDate : {}, endDate : {}, userId : {}.", userType, beginDate, endDate, userId2);
                        SUser user = this.getUserService().selectByPrimaryKey(userId2);
                        LOGGER.info("send bill message params userType : {}, beginDate : {}, endDate : {}, user : {}.", userType, beginDate, endDate, user);
                        String phone = "13693611373";
                        if (null != user) {
                            phone = user.getPhone();
                        }
                        BigDecimal amount = cBill.getAmount().abs();
                        long tplId = JavaSmsApi.KELECOMPANY_BILL_TPL_ID;

                        String tpl_value = URLEncoder.encode("#amount#", JavaSmsApi.getENCODING()) + "=" + URLEncoder.encode(amount.toString(), JavaSmsApi.getENCODING());

                        this.getSendMessageService().sendMessage(tplId, tpl_value, phone);
                    }
                }
            }
        } catch (Exception e) {
            LOGGER.error("send bill message params userType : {}, beginDate : {}, endDate : {}, error : {}.", userType, beginDate, endDate, e);
            throw new BusinessException("商户账单发送短信异常");
        }
    }

    @Override
    public BillBFiles generateShareUrl4File(Long billId) {
        LOGGER.info("select bill files params billId : {}.", billId);
        List<Long> billIds = this.getBillIds(billId);
        List<BFiles> bFiles = this.getBFilesService().selectByBillids(billIds);
        if (CollectionUtils.isEmpty(bFiles) || bFiles.size() < billIds.size()) {
            return null;
        }
        String fileName = bFiles.get(0).getRealName();
        // String desc = bFiles.getDescription();
        // String url =  "http://"+App.KYLEBUSS_CONTENTPATH+"/file/download/"+HYCUtils.encryptBankCard(billId+"")+"/"+HYCUtils.encryptBankCard(new Date().getTime()+"");
        String url = "http://" + HYCUtils.getConstantPropertiesLoader().getProperty(App.KYLEBUSS_CONTENTPATH) + "/file/download/" + HYCUtils.encryptBankCard(billId + "") + "/" + HYCUtils.encryptBankCard(new Date().getTime() + "");
        BillBFiles billBFiles = new BillBFiles();
        billBFiles.setRealName(fileName);
        String desc = "[慧运车]尊敬的客户，" + bFiles.get(0).getDescription() + "账单已生成，请访问链接" + url + "下载或查看，该链接24小时后自动失效！";
        billBFiles.setDesc(desc);
        billBFiles.setUrl(url);
        LOGGER.info("select bill files params billId : {}, billBFiles : {}.", billId, billBFiles);
        return billBFiles;
    }

    @Override
    public List<CBillAdminVo> getBills(CBillAdminVo bill, int userType) {
        LOGGER.info("select bills params page:{}, userType:{}.", userType);
        Map<String, Object> paramsMap = new HashMap<>();
        paramsMap.put("limitStart", null);
        paramsMap.put("limitEnd", -1);

        if (null != bill) {
            paramsMap.put("userType", bill.getUserType());
            paramsMap.put("userName", bill.getUserName());
            paramsMap.put("phone", bill.getPhone());
            paramsMap.put("status", bill.getStatus());
            if (StringUtils.isNotBlank(bill.getBeginDateParam()) && !bill.getBeginDateParam().equalsIgnoreCase("null")) {
                paramsMap.put("beginDate", DateUtils.StrToDate(bill.getBeginDateParam(), DateUtils.FORMAT_DATETIME));
            }
            if (StringUtils.isNotBlank(bill.getEndDateParam()) && !bill.getEndDateParam().equalsIgnoreCase("null")) {
                paramsMap.put("endDate", DateUtils.StrToDate(bill.getEndDateParam(), DateUtils.FORMAT_DATETIME));
            }
        }
        return this.getcBillViewMapper().selectByConditions(paramsMap);
    }

    @Override
    public List<String[]> exportDriverWithdrawalApplication(CBillAdminVo bill, int userType, int length) {
        LOGGER.info("select driverWithdrawalApplication export params length : {}.", length);
        List<CBillAdminVo> cbs = this.getBills(bill, userType);
        //定义一个数组型的list列表
        List<String[]> list = new ArrayList<String[]>();
        String str[] = null;
        if (null != cbs) {
            for (CBillAdminVo c : cbs) {
                str = new String[10];
                str[0] = String.valueOf(c.getId());        //账单编号
                str[1] = String.valueOf(c.getUserId());    //账户ID
                str[2] = c.getUserName();                //账户名称
                str[3] = c.getPhone();                    //电话
                str[4] = String.valueOf(c.getAmount());    //账单金额
                str[5] = DateUtils.getStringFromDate(c.getBeginDate(), DateUtils.FORMAT_DATETIME);    //开始日期
                str[6] = DateUtils.getStringFromDate(c.getEndDate(), DateUtils.FORMAT_DATETIME);        //结束日期
                str[7] = "周";                            //账期
                str[8] = AccBillStatusEnum.getByValue(NumberUtils.toInt(c.getStatus())).getText();                    //状态
                str[9] = DateUtils.getStringFromDate(c.getCreateTime(), DateUtils.FORMAT_DATETIME);    //创建时间
                list.add(str);
            }
        }
        return list;
    }

}